﻿using System.Linq;
using System.Xml;

namespace Renci.Data.Interop.Serialization
{
    public partial class InteropSerializer
    {
        private static void HandleReadAttributes(System.Xml.XmlReader reader, object obj)
        {
            //  TODO:   Handle XmlSchemaForm attribute proeprty if required
            var propertiesToAttributesMap = GetPropertiesAttributeMap(obj.GetType());

            //  Handle all node attributes 
            if (reader.MoveToFirstAttribute())
            {
                do
                {
                    var propertyAttribute = (from prop in propertiesToAttributesMap.OfType<PropertyAttributeSerializationInfo>()
                                             where
                                                prop.IsAttribute
                                                && prop.Name.Name == reader.LocalName
                                                && (string.IsNullOrEmpty(reader.NamespaceURI) || prop.Name.Namespace == reader.NamespaceURI)
                                             select prop).SingleOrDefault();

                    if (propertyAttribute != null)
                    {
                        var value = reader.GetAttribute(propertyAttribute.Name.Name, propertyAttribute.Name.Namespace) ?? reader.GetAttribute(propertyAttribute.Name.Name);

                        propertyAttribute.SetPropertyValue(obj, value);
                    }

                } while (reader.MoveToNextAttribute());
            }
            reader.MoveToElement();
        }

        private static void HandleReadNodeElement(System.Xml.XmlReader reader, object obj)
        {
            var propertiesToAttributesMap = GetPropertiesAttributeMap(obj.GetType());

            var qn = new XmlQualifiedName(reader.LocalName, reader.NamespaceURI);
            var arrayElementInfo = (from prop in propertiesToAttributesMap
                                    where
                                        prop.ArrayRootAttribute != null
                                        && prop.ArrayRootAttribute.Name == qn
                                    select prop).SingleOrDefault();

            if (arrayElementInfo != null)
            {
                var arrayReader = reader.ReadSubtree();

                while (arrayReader.Read())
                {
                    if (arrayReader.NodeType == XmlNodeType.Element)
                    {
                        var arrayQn = new XmlQualifiedName(arrayReader.LocalName, arrayReader.NamespaceURI);

                        var arrayItemElementInfo = (from prop in propertiesToAttributesMap.OfType<PropertyAttributeSerializationInfo>()
                                                    where
                                                        prop.IsArrayItem
                                                        && prop.Name == arrayQn
                                                    select prop).SingleOrDefault();

                        if (arrayItemElementInfo != null)
                        {
                            //  Get property value
                            var value = arrayItemElementInfo.GetComplexValue(reader);

                            //  Set property value
                            arrayElementInfo.SetPropertyValue(obj, value);
                            continue;
                        }
                    }
                }

                return;
            }


            //  Proccess all other elements
            var elementInfo = (from prop in propertiesToAttributesMap.OfType<PropertyAttributeSerializationInfo>()
                               where
                                prop.IsElement
                                && prop.Name == qn
                               select prop
                               ).SingleOrDefault();

            if (elementInfo != null)
            {
                //  Get value
                var value = elementInfo.GetComplexValue(reader);

                //  Set property value
                elementInfo.SetPropertyValue(obj, value);

                return;
            }
        }

        private static void HandleReadTextElement(System.Xml.XmlReader reader, object obj)
        {
            var propertiesToAttributesMap = GetPropertiesAttributeMap(obj.GetType());

            var textInfo = (from prop in propertiesToAttributesMap
                            where prop.IsText
                            select prop).SingleOrDefault();

            if (textInfo != null)
            {
                textInfo.SetPropertyValue(obj, reader.Value);
            }
        }
    }
}
